package cn.lm.activit.module;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.DeploymentQueryImpl;
import org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.testng.collections.Lists;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lm_jcf
 * @date 2018/7/13 11:09
 */
public class DemGateway {

    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    @Test
    public void testProcess() {
        // 引擎配置
        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                .setJdbcUrl("jdbc:mysql://localhost:3306/activiti-test?user=root&password=&useUnicode=true&characterEncoding=gbk&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true")
                .setJdbcUsername("root")
                .setJdbcPassword("root")
                .setJdbcDriver("com.mysql.jdbc.Driver")
                .setDatabaseSchema("ACT")
                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
                .setActivityFontName("宋体")
                .setLabelFontName("宋体")
                .setDatabaseCatalog("activiti-init-data");
        // 获取流程引擎对象
        ProcessEngine processEngine = cfg.buildProcessEngine();
    }

    @Test
    public void initActivitiData() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        processEngine.getProcessEngineConfiguration().buildProcessEngine();

    }

    @Test
    public void deploymentProcessDefinition() {
        Deployment deployment = processEngine.getRepositoryService()    //与流程定义和部署对象相关的额Service
                .createDeployment()     //创建一个部署对象
                .name("测试分支")
//                .addClasspathResource("bpmn/dem_gateway.bpmn")    //加载资源dpmn
                .addClasspathResource("bpmn/exclusive_gateway.bpmn")    //加载资源dpmn
//                .addClasspathResource("bpmn/m-model-key.bpmn")    //加载资源dpmn
                .deploy();   //完成部署

        System.out.println("流程Id" + deployment.getId());
        System.out.println("流程名称" + deployment.getName());

    }

    @Test
    public void operateDeployment() {
        //        processEngine.getRepositoryService().setDeploymentKey("1","dem_gateway");
        Deployment deployment = processEngine.getRepositoryService()
                .createDeploymentQuery()
                .deploymentKey("dem_gateway").singleResult();

        String deploymentId = deployment.getId();

        ProcessDefinition processDefinition = processEngine.getRepositoryService()
                .createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();

        String processDefinitionId = processDefinition.getId();
        System.out.println(processDefinition.getId());

        System.out.println("=================================");

        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);

        List<Process> processList = bpmnModel.getProcesses();
        for (Process process : processList) {
            Collection<Artifact> artifacts = process.getArtifacts();
            for (Artifact artifact : artifacts) {
                System.out.println(artifact.getId());
            }
        }


    }

    public static void main(String[] args) {
        System.out.println("11<23");

        List<String> list = Lists.newArrayList();

        list.add("22");
        list.add("22");
        list.add("22");

        list.add(0, "33");

        List<Integer> collect = list.stream().map(Integer::parseInt).collect(Collectors.toList());

        System.out.println(collect);
        System.out.println(StringUtils.join(list,"&&"));


        Map<String, String> map = Maps.newConcurrentMap();
        map.put("金额", "2000");

        System.out.println(JSON.toJSONString(map));
    }


    @Test
    public void startProcessInstance() {
//        String processKey = "dem_gateway";
        String processKey = "exclusive_gateway_process";
//        String processKey = "m-model-key";

        Map<String, Object> params = new HashMap<String, Object>();
//        params.put("assigneeId", "第一审批人");
//        params.put("money", 10);
//        params.put("param", 22);
        ProcessInstance pi = processEngine.getRuntimeService()      //与正在执行的流程实例和执行对象相关的Service
                .startProcessInstanceByKey(processKey, params);     //使用流程定义的Key启动流程实例，可以使之每次都启动最新版本的流程。

        System.out.println("流程实例ID：" + pi.getId());
        System.out.println("流程定义ID：" + pi.getProcessDefinitionId());

    }

    @Test
    public void findInvolve() {
        String assignee = "jcf";

        List<HistoricProcessInstance> hiProcInst = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
//                .startedBy(assignee)
                .involvedUser(assignee)
                .orderByProcessInstanceStartTime().desc()
                .list();
        if (hiProcInst != null && hiProcInst.size() > 0) {
            for (HistoricProcessInstance task : hiProcInst) {
                System.out.println(task.getId());
                System.out.println(task.getEndTime());
                System.out.println(task.getStartUserId());
                System.out.println("------");
            }
        }
    }

    @Test
    public void test() {
        String taskId = "";
        Task targetTask = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) processEngine.getRepositoryService()
                .getProcessDefinition(targetTask.getProcessDefinitionId());

    }

    @Test
    public void findMeHandle() {
        String assignee = "江一";

        List<HistoricTaskInstance> hiUserTasks = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
                .taskAssignee(assignee)
                .list();

        if (hiUserTasks != null && hiUserTasks.size() > 0) {
            for (HistoricTaskInstance task : hiUserTasks) {
                System.out.println(task.getId());
                System.out.println(task.getEndTime());
                System.out.println(task.getProcessInstanceId());
                System.out.println("------");
            }
        }
    }

    @Test
    public void findBpmnModel(){
        String processKey = "m-model-key";
        ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery()
                .processDefinitionKey(processKey).latestVersion().singleResult();

        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinition.getId());

        List<Process> processes = bpmnModel.getProcesses();
        for (Process process : processes) {
            for (FlowElement flowElement : process.getFlowElements()) {
                System.out.println(flowElement.getName());
            }

            List<UserTask> userTaskList = process.findFlowElementsOfType(UserTask.class, true);
            if (CollectionUtil.isNotEmpty(userTaskList)) {
                for (UserTask userTask : userTaskList) {
                    Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
                }
            }
        }
        System.out.println(processes);
        System.out.println(bpmnModel);

    }


    @Test
    public void findMyProcessTask() {
        String assignee = "第二位审批人";
        List<Task> list = processEngine.getTaskService()  //与正在执行的任务相关的Service
                .createTaskQuery()  //创建任务查询对象
                /** 查询条件  */
                .taskAssignee(assignee) //指定个人任务对象
//                .taskCandidateUser(taskCandidateUser) //组任务的办理人
//                .processDefinitionId()  //使用流程定义Id查询
//                .processInstanceId()    //使用流程实例ID
//                .executionId()  //使用执行对象id查询
                /** 排序*/
                .orderByTaskCreateTime().asc()  //使用创建时间升序排序
                /** 返回结果集*/
//                .singleResult()   //唯一结果集
//                .count()  //返回结果集的数量
//                .listPage()   //分页查询
                .list();

        if (list != null && list.size() > 0) {
            for (Task task : list) {
                System.out.println("任务ID:" + task.getId());
                System.out.println("任务名称:" + task.getName());
                System.out.println("任务创建时间:" + task.getCreateTime());
                System.out.println("任务办理人:" + task.getAssignee());
                System.out.println("流程实例ID:" + task.getProcessInstanceId());
                System.out.println("执行对象ID:" + task.getExecutionId());
                System.out.println("流程定义ID:" + task.getProcessDefinitionId());
                System.out.println("当前任务节点模型ID:" + task.getTaskDefinitionKey());

                List<HistoricActivityInstance> activityList = processEngine.getHistoryService()
                        .createHistoricActivityInstanceQuery()
//                        .taskAssignee(task.getAssignee())
                        .activityId(task.getTaskDefinitionKey())
                        .list();
                for (HistoricActivityInstance activity : activityList) {
                    System.out.println("任务实例ID：" + activity.getId());
                    System.out.println("模型元素ID：" + activity.getActivityId());
                    System.out.println("模型元素名称：" + activity.getActivityName());
                    System.out.println(activity.getTaskId());
                }

                Execution execution = processEngine.getRuntimeService()
                        .createExecutionQuery()
                        .executionId(task.getExecutionId())
                        .singleResult();
                System.out.println("当前执行对象中的模型元素ID:" + execution.getActivityId());
                System.out.println("当前执行对象中的模型元素ID:" + execution.getId());



               /* System.out.println("-------------");

               // 未解决 org.activiti.engine.ActivitiException: Found Activiti 5 process definition, but no compatibility handler on the classpath
                Process process = ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId());

                System.out.println(process.getName());
                Collection<FlowElement> e = process.getFlowElements();
                for (FlowElement flowElement : e) {
                    System.out.println(flowElement.getId()+ "--"+flowElement.getName());
                }*/

//                FlowElement flowElement = processEngine.getManagementService()
            }
        }
    }


    @Test
    public void queryHiTask() {
        String procInstId = "62501";

        List<HistoricTaskInstance> list = processEngine.getHistoryService()
                .createHistoricTaskInstanceQuery()
                .processInstanceId(procInstId)
                .list();

        if (list != null) {
            for (HistoricTaskInstance task : list) {
                System.out.println("任务ID:" + task.getId());
                System.out.println("任务名称:" + task.getName());
                System.out.println("任务创建时间:" + task.getCreateTime());
                System.out.println("任务办理人:" + task.getAssignee());
                System.out.println("流程实例ID:" + task.getProcessInstanceId());
                System.out.println("执行对象ID:" + task.getExecutionId());
                System.out.println("流程定义ID:" + task.getProcessDefinitionId());
                System.out.println("当前任务节点模型ID:" + task.getTaskDefinitionKey());
                System.out.println(task.getEndTime());
                System.out.println("------");
            }
        }
    }

    @Test
    public void findActivityByExecutionIdAndTaskKey() {
        String activityId = "_4";
        String procInstId = "62501";


        List<HistoricActivityInstance> list = processEngine.getHistoryService()
//                .createNativeHistoricActivityInstanceQuery()
                .createHistoricActivityInstanceQuery()
                .activityId(activityId)
                .processInstanceId(procInstId)
//                .sql(customSql)
                .list();
        if (list != null) {
            for (HistoricActivityInstance hi : list) {
                System.out.println(hi.getId());
                System.out.println(hi.getAssignee());
                System.out.println(hi.getActivityName());
                System.out.println(hi.getTaskId());
            }
        }
    }

    @Test
    public void customQuerySql() {
        String taskId = "72506";
        String twoTaskId = "75002";
        String customSql = "select * from act_hi_actinst where TASK_ID_ in (#{taskId},#{twoTaskId})";
        List<HistoricActivityInstance> list = processEngine.getHistoryService()
                .createNativeHistoricActivityInstanceQuery()
                .sql(customSql)
                .parameter("taskId", taskId)
                .parameter("twoTaskId", twoTaskId)
                .list();

        if (list != null) {
            List<String> activityIds = new ArrayList<String>();
            for (HistoricActivityInstance activity : list) {
                System.out.println("任务实例ID：" + activity.getId());
                System.out.println("模型元素ID：" + activity.getActivityId());
                System.out.println("模型元素名称：" + activity.getActivityName());
                System.out.println("任务ID：" + activity.getTaskId());
                activityIds.add(activity.getId());
            }

            if (activityIds.size() > 0) {
                String deleteSql = "delete from act_hi_actinst where ID_ in(%s)";
//                String ids = StringUtils.join(activityIds,",");
                deleteSql = String.format(deleteSql, StringUtils.join(activityIds, ","));
                processEngine.getHistoryService()
                        .createNativeHistoricActivityInstanceQuery()
                        .sql(deleteSql)
//                        .parameter("ids", ids)
                        .singleResult();

            }
        }
    }

    @Test
    public void jump() {
        String currentTaskId = "110002";
        String targetTaskId = "100002";

        processEngine.getManagementService()
                .executeCommand(new TurnProcHandle(currentTaskId, targetTaskId));

    }

    @Test
    public void deleteProc() {
        String procInstId = "72501";
        processEngine.getRuntimeService().deleteProcessInstance(procInstId, "删除");
        processEngine.getHistoryService().deleteHistoricProcessInstance(procInstId);
    }

    @Test
    public void deleteHiTask() {
        String taskId = "25001";
        processEngine.getHistoryService()
                .deleteHistoricTaskInstance(taskId);
    }

    @Test
    public void findHiActivityInst() {
        String activityId = "32502";
        List<HistoricActivityInstance> list = processEngine.getHistoryService()
                .createHistoricActivityInstanceQuery()
                .activityId(activityId)
                .list();

        for (HistoricActivityInstance hi : list) {
            System.out.println(hi.getTaskId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getAssignee());
        }
    }

    @Test
    public void completeMyProcessTask() {
        String taskId = "167504";

        Map<String, Object> params = new HashMap<String, Object>();
//        params.put("assigneeId", "第三位审批人");
//        params.put("money", 10);
//        params.put("param", "220");
        params.put("money", "0");
        processEngine.getTaskService()
                .complete(taskId,params);
        System.out.println("完成任务");
    }
}
